﻿//-----------------------------------------------------------------------------------------------------------
// WBFSSync Project by Omega Frost 
// http://wbfssync.codeplex.com/
//
// WBFSSync is Licensed under the terms of the 
// Microsoft Reciprocal License (Ms-RL)
//-----------------------------------------------------------------------------------------------------------
using System;
using System.IO;
using System.Net;
using System.Text;

namespace WBFSe3.Wbfs
{
    public static class WbfsHelper
    {
        #region Byte Ordering

        //------------------------------------------------------------------------------------------
        // 
        //------------------------------------------------------------------------------------------
        public static short ntohs(short value)
        {
            return IPAddress.NetworkToHostOrder(value);
        }


        //------------------------------------------------------------------------------------------
        // 
        //------------------------------------------------------------------------------------------
        public static ushort ntohs(ushort value)
        {
            return (ushort)IPAddress.NetworkToHostOrder((short)value);
        }


        //------------------------------------------------------------------------------------------
        // 
        //------------------------------------------------------------------------------------------
        public static short ntohs(Byte[] value, int index)
        {
            return IPAddress.NetworkToHostOrder(BitConverter.ToInt16(value, index));
        }


        //------------------------------------------------------------------------------------------
        // 
        //------------------------------------------------------------------------------------------
        public static int ntohi(int value)
        {
            return IPAddress.NetworkToHostOrder(value);
        }


        //------------------------------------------------------------------------------------------
        // 
        //------------------------------------------------------------------------------------------
        public static uint ntohi(uint value)
        {
            return (uint)IPAddress.NetworkToHostOrder((int)value);
        }


        //------------------------------------------------------------------------------------------
        // 
        //------------------------------------------------------------------------------------------
        public static int ntohi(Byte[] value, int index)
        {
            return IPAddress.NetworkToHostOrder(BitConverter.ToInt32(value, index));
        }


        //------------------------------------------------------------------------------------------
        // 
        //------------------------------------------------------------------------------------------
        public static long ntohl(long value)
        {
            return IPAddress.NetworkToHostOrder(value);
        }


        //------------------------------------------------------------------------------------------
        // 
        //------------------------------------------------------------------------------------------
        public static ulong ntohl(ulong value)
        {
            return (ulong)IPAddress.NetworkToHostOrder((long)value);
        }


        //------------------------------------------------------------------------------------------
        // 
        //------------------------------------------------------------------------------------------
        public static long ntohl(Byte[] value, int index)
        {
            return IPAddress.NetworkToHostOrder(BitConverter.ToInt64(value, index));
        }


        //------------------------------------------------------------------------------------------
        // 
        //------------------------------------------------------------------------------------------
        public static short htons(short value)
        {
            return IPAddress.HostToNetworkOrder(value);
        }


        //------------------------------------------------------------------------------------------
        // 
        //------------------------------------------------------------------------------------------
        public static ushort htons(ushort value)
        {
            return (ushort)IPAddress.HostToNetworkOrder((short)value);
        }


        //------------------------------------------------------------------------------------------
        // 
        //------------------------------------------------------------------------------------------
        public static int htoni(int value)
        {
            return IPAddress.HostToNetworkOrder(value);
        }


        //------------------------------------------------------------------------------------------
        // 
        //------------------------------------------------------------------------------------------
        public static uint htoni(uint value)
        {
            return (uint)IPAddress.HostToNetworkOrder((int)value);
        }


        //------------------------------------------------------------------------------------------
        // 
        //------------------------------------------------------------------------------------------
        public static long htonl(long value)
        {
            return IPAddress.HostToNetworkOrder(value);
        }


        //------------------------------------------------------------------------------------------
        // 
        //------------------------------------------------------------------------------------------
        public static ulong htonl(ulong value)
        {
            return (ulong)IPAddress.HostToNetworkOrder((long)value);
        }

        #endregion

        #region Readers

        //------------------------------------------------------------------------------------------
        // Reads a string from a stream
        //------------------------------------------------------------------------------------------
        public static string ReadString(Stream stream, ushort maximum)
        {
            Byte[] buffer = new Byte[maximum];
            stream.Read(buffer, 0, maximum);

            StringBuilder builder = new StringBuilder(maximum);
            for (int i = 0; i < maximum; i++)
            {
                if (buffer[i] == 0)
                {
                    stream.Position -= (maximum - builder.Length);
                    buffer = null;
                    return builder.ToString();
                }
                else
                {
                    builder.Append((char)buffer[i]);
                }
            }

            stream.Position -= (maximum - builder.Length);
            buffer = null;
            return builder.ToString();
        }


        //------------------------------------------------------------------------------------------
        // Reads a string from a byte array
        //------------------------------------------------------------------------------------------
        public static string ReadString(Byte[] bytes, int offset)
        {
            StringBuilder builder = new StringBuilder();
            for (int i = offset; i < bytes.Length; i++)
            {
                if (bytes[i] == 0)
                {
                    break;
                }
                else
                {
                    builder.Append((char)bytes[i]);
                }
            }

            return builder.ToString();
        }


        //------------------------------------------------------------------------------------------
        // Reads a string from a byte array
        //------------------------------------------------------------------------------------------
        public static string ReadString(Byte[] bytes, int offset, ushort maximum)
        {
            StringBuilder builder = new StringBuilder();
            int to = Math.Min(offset + maximum, bytes.Length);
            for (int i = offset; i < to; i++)
            {
                if (bytes[i] == 0)
                {
                    break;
                }
                else
                {
                    builder.Append((char)bytes[i]);
                }
            }

            return builder.ToString();
        }

        #endregion

        #region Converters

        //------------------------------------------------------------------------------------------
        // Converts a power-of-2 number to a number of left shifts
        //------------------------------------------------------------------------------------------
        public static byte lshs(int n)
        {
            byte count = 0;
            while (n != 1)
            {
                n >>= 1;
                count++;
            }
            return count;
        }


        //------------------------------------------------------------------------------------------
        // Converts a power-of-2 number to a number of left shifts
        //------------------------------------------------------------------------------------------
        public static int WbfsSecsPerDisc(int wbfssectorsize)
        {
            int wiiSecsPerWbfsSec = wbfssectorsize >> WbfsConstants.WiiSectorSizeLSh;
            return WbfsConstants.WiiSectorsPerDisc / wiiSecsPerWbfsSec;
        }


        //------------------------------------------------------------------------------------------
        // Calculates the maximum number of wbfs sectors on a Wii disc
        //------------------------------------------------------------------------------------------
        public static int WbfsSecsLshPerDisc(int wbfssectorsizelsh)
        {
            int wiiSecsPerWbfsSecLsh = wbfssectorsizelsh - WbfsConstants.WiiSectorSizeLSh;
            return WbfsConstants.WiiSectorsPerDisc >> wiiSecsPerWbfsSecLsh;
        }


        //------------------------------------------------------------------------------------------
        // Alinha uma posição num determinado tamanho de setor
        //------------------------------------------------------------------------------------------
        public static long Align(long a, long b)
        {
            return (a / b) * b;
        }


        //------------------------------------------------------------------------------------------
        // Alinha uma posição num determinado tamanho de setor
        //------------------------------------------------------------------------------------------
        public static int Align(int a, int b)
        {
            return (a / b) * b;
        }


        //------------------------------------------------------------------------------------------
        // Retorna o menor tamanho alinhado para comportar determinado tamanho
        //------------------------------------------------------------------------------------------
        public static long Fit(long a, long b)
        {
            return (((a - 1) / b) + 1) * b;
        }


        //------------------------------------------------------------------------------------------
        // Retorna o menor tamanho alinhado para comportar determinado tamanho
        //------------------------------------------------------------------------------------------
        public static int Fit(int a, int b)
        {
            return (((a - 1) / b) + 1) * b;
        }


        //------------------------------------------------------------------------------------------
        // Igual à rotina fit(...) porém aceita como entrada bits e retorna em bytes
        //------------------------------------------------------------------------------------------
        public static long FitBit(long a, long b)
        {
            return (((a - 1) / b) + 1);
        }


        //------------------------------------------------------------------------------------------
        // Igual à rotina fit(...) porém aceita como entrada bits e retorna em bytes
        //------------------------------------------------------------------------------------------
        public static int FitBit(int a, int b)
        {
            return (((a - 1) / b) + 1);
        }


        //------------------------------------------------------------------------------------------
        // Calculates the maximum number of wbfs sectors on a Wii disc
        //------------------------------------------------------------------------------------------
        public static WbfsRegion GetRegionFromCode(string code)
        {
            return GetRegionFromCode((byte)(Char.ToLowerInvariant(code[3])));
        }


        //------------------------------------------------------------------------------------------
        // Converts a region byte to a region code
        //------------------------------------------------------------------------------------------
        public static WbfsRegion GetRegionFromCode(byte regionbyte)
        {
            //Convert to uppercase
            if (regionbyte > 90)
                regionbyte -= 20;

            switch (regionbyte)
            {
                case 0x41: return WbfsRegion.RegionFree;
                case 0x43: return WbfsRegion.Custom;
                case 0x44: return WbfsRegion.PALGerman;
                case 0x45: return WbfsRegion.NTSCU;
                case 0x46: return WbfsRegion.PALFrench;
                case 0x4A: return WbfsRegion.NTSCJ;
                case 0x4B: return WbfsRegion.KOR;
                case 0x4C: return WbfsRegion.PALWorld;
                case 0x50: return WbfsRegion.PAL;
                case 0x51: return WbfsRegion.KORJapanese;
                case 0x54: return WbfsRegion.KOREnglish;
                case 0x58: return WbfsRegion.PALOther;
                default: return WbfsRegion.Unknown;
            }
        }


        //------------------------------------------------------------------------------------------
        // 
        //------------------------------------------------------------------------------------------
        public static WbfsUsage CreateWbfsUsage(int sectorSize, WbfsUsage wiiSectors)
        {
            int ndiv = (sectorSize >> WbfsConstants.WiiSectorSizeLSh);
            int nsecs = WbfsConstants.WiiSectorsPerDisc / ndiv;

            Boolean[] sectors = new Boolean[nsecs];
            for (int i = 0; i < nsecs; i++)
            {
                int p = ndiv * i;
                for (int j = 0; j < ndiv; j++)
                {
                    if (wiiSectors[p + j])
                        sectors[i] = true;
                }
            }

            return new WbfsUsage(sectors);
        }

        #endregion
    }
}
